package com.AdvancedDemos;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.function.IntToDoubleFunction;

public class Arrays类 {
    public static void main(String[] args) {
        /**
         * Arrays类是一个操作数组的工具类
         *
         * public static String toString(T[] arr) --- 返回数组的字符串形式内容
         * public static T[] copyOfRange(T[] arr,起始索引,结束索引) --- 拷贝数组(指定范围,包前不包后)
         * public static T[] copyOf(T[] arr,int newLength) --- 拷贝数组,同时指定新数组的长度,一般用作数组扩容
         * public static setAll(double[] array, IntToDoubleFunction generator) --- 把数组中的原数据改为新数据
         * public static void sort(T[] arr) --- 对数组进行排序(默认是升序排序)
         */

        int[] arr = new int[]{10, 20, 30, 40, 50};
        System.out.println(Arrays.toString(arr));//[10, 20, 30, 40, 50]

        int[] copyArr1 = Arrays.copyOfRange(arr, 1, 4);//包头不包尾
        System.out.println(Arrays.toString(copyArr1));

        int[] copyArr2 = Arrays.copyOf(arr, 10);//指定新数组长度为10,不足部分用默认值赋值,
        /*
         * 动态初始化数组元素默认值规则:
         * 基本类型:
         * byte,short,char,int,long 为 0
         * float,double 为 0.0
         * boolean 为 false
         * 引用类型:
         * 类,接口,数组,String 为 null
         * */
        //当指定长度小于原数组时,将截短复制
        System.out.println(Arrays.toString(copyArr2));


        System.out.println("------------");
        double[] prices = {99.8, 128, 100};
        //把所有价格都打八折,然后又存回去
        Arrays.setAll(prices, new IntToDoubleFunction() {
            @Override
            public double applyAsDouble(int value) {//代表数组下标,从0开始依次遍历
                return prices[value] * 0.8;//该处理后的返回值将被回填到原来的元素位置
            }
        });
        System.out.println(Arrays.toString(prices));


        System.out.println("------------");
        Arrays.sort(prices);//数组排序默认升序
        System.out.println(Arrays.toString(prices));

        /**
         * 如果直接调用sort会对基本型数组进行升序排序
         *
         * 如果是对象数组进行排序,有两个方式
         * 方式1 自然排序:
         * 需要让数组元素类实现Comparable<T>接口,指定泛型类型为数组元素自身类型即可,然后重写public int compareTo(T o)函数,用于比较两个数组元素的大小,将来Arrays.sort(数组名)内部会调用compareTo函数,从而确定大小顺序,在函数体中手动指定比较规则(具体按照元素类型的哪一个属性排序),具体见下文函数重写处
         */
        Student[] students = new Student[4];
        students[0] = new Student("王24352", 1, 25);
        students[1] = new Student("张26446", 2, 23);
        students[2] = new Student("李29579", 3, 18);
        students[3] = new Student("黄40644", 4, 20);
        System.out.println("原数组:" + Arrays.toString(students));
        Arrays.sort(students);
        System.out.println("按age升序排序后:" + Arrays.toString(students));


        System.out.println("----------------");
        /** 方式2 比较器排序:
         * 无需数组元素类实现Comparable<T>接口,而是使用另一带泛型的sort方法,public static <T> void sort(T[] arr, Comparator<? super T> c) 对数组进行排序,创建Comparator比较器接口的匿名内部类对象,也支持自定义排序规则
         */
//        public static <T> void sort(T[] arr, Comparator<? super T> c)
//        参数1:待排序数组
//        参数2:Comparator比较器对象,用于制定对象的比较规则

        Arrays.sort(students, new Comparator<Student>() {
            @Override
            public int compare(Student o1, Student o2) {
                /*默认升序排序约定:
                当认为 o1 > o2 时 返回正整数
                当认为 o1 < o2 时 返回负整数
                当认为 o1 == o2 时 返回整数0*/

            /*    if (o1.getName().compareTo(o2.getName()) > 0) {
                    return 1;
                } else if (o1.getName().compareTo(o2.getName()) < 0) {
                    return -1;
                } else {
                    return 0;
                }*/

                //等价于
                return o1.getName().compareTo(o2.getName());//降序调换顺序即可

//                如果是两个double可以如下
//              retrun Double.compare(double1,double2);
            }
        });
        System.out.println("按name升序排序后:" + Arrays.toString(students));


        System.out.println("---------------");
        //可变参数简化参数设计(JDK新特性)
        //注意如果参数列表存在多个参数,可变参数必须在最右边
        show(10, 20, 30);
        show(new int[5]);


        System.out.println("---------------");
        //数组与集合ArrayList互转

        //数组 -> 集合
        //public static <T> List<T> asList(T... a)
        //Arrays.asList返回类是内部类ArrayList，此ArrayList内部存在final类型的数组来接收入参数组T，此ArrayList不支持add，remove等方法，不支持扩容
        //Arrays.asList()产生的list并不是ArrayList或者LinkedList,而是一个一个特殊的list实现类对象,它产生后:
        //1.不允许添加 2.不允许修改 3.不允许删除 4.只可以获取元素值
        //所以通常作为参数传递,来批量添加集合元素

        Integer[] arr1 = {1, 2, 3, 4, 5};
        List<Integer> integers = Arrays.asList(arr1);//可变参数可以用多个变量作为实参,也可以用数组作为实参
        ArrayList<Integer> list = new ArrayList<>(integers);
//        /*或者*/list.addAll(integers);
        System.out.println(list);

        //集合 -> 数组
        //借助toArray(T[] arr)
        //方法实际参数需要传递集合元素类型的数组
        //长度 < 集合元素个数 创建新的与集合元素个数相同的数组存储数据,如果将数组长度指定为0则意为只指定类型,长度等于集合元素
        //长度 >= 集合元素个数,直接使用参数数组存储数据
        Integer[] integers1 = new Integer[10];
        Integer[] integers2 = list.toArray(integers1);//将集合对象list转成数组存入integers1,再将integers1的地址赋给integers2,两者是同一个数组
        System.out.println(Arrays.toString(integers1));
        System.out.println(Arrays.toString(integers2));
        System.out.println(integers1 == integers2);//toArray返回的就是intergers1对象自身的地址


    }//<---------main

    public static void show(int... nums) {
        //函数内部nums直接当数组使用
        for (int i = 0; i < nums.length; i++) {
            int num = nums[i];
            System.out.print(num + " ");
        }
        System.out.println();
    }
}


class Student implements Comparable<Student> {
    String name;
    int id;
    int age;

    public Student() {
    }

    public Student(String name, int id, int age) {
        this.name = name;
        this.id = id;
        this.age = age;
    }

    @Override
    public int compareTo(Student o) {
        /**
         * this与o进行比较,默认升序
         * 如果 返回正整数 认为this > o
         * 如果 返回负整数 认为this < o
         * 如果 返回整数0 认为this == o
         *
         * 要实现降序排序只需要将 > < 情况下的返回值取反即可
         */

        /*if (this.age > o.age) {
            return 1;
        } else if (this.age < o.age) {
            return -1;
        } else {
            return 0;
        }*/
        //实际上此处的逻辑可以简化为
        return this.age - o.age;//当 this.age > o.age 则自动返回正数,当 this.age < o.age 则自动返回负数,当 this.age == o.age 则自动返回0
//        return o.age - this.age;


        //实现多条件排序
        //String类拥有自然排序规则,可以使用重写的compareTo()按照对应位置字符值从小到大排序
        /*
        int result = this.name.compareTo(o.name);//优先按照姓名升序排序
        if (result == 0) {//当姓名相同时
            result = o.age - this.age;//再按照年龄逆序排序
        }
         */
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", id=" + id +
                ", age=" + age +
                '}';
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

}
